﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Dtf.Core.Remoting;

namespace Dtf.Core
{
    public class UIFilter : RemotingObject, ICloneable
    {
        public UIFilter(string filterString)
        {
            if (_regex == null)
            {
                _regex = new Regex("(?<name>([A-Za-z]+))[ ]*(?<cmpOp>=|(!=)){1}[ ]*(?<value>([']{1}[^']*[']{1})|[0-9]+|true)($|([ ]*(?<join>[&||]{2})[ ]*))");

            }
            if (!_regex.IsMatch(filterString))
            {
                throw new FilterExecption("Invalid filter string: " + filterString);
            }

            _filters = new List<UIFilter>();
            _strfilter = filterString;
            _type = Join_Type.Join_And;
        }

        public void Join(UIFilter filter, Join_Type type)
        {
            _filters.Add(filter.Clone() as UIFilter);

        }

        public bool IsMatch(UIItem item)
        {
            bool bLastRet;
            bLastRet = IsMatchSelf(item);
            foreach(UIFilter filter in _filters)
            {
                Join_Type type = filter._type;
                if (!bLastRet && filter._type==Join_Type.Join_And)
                {
                    continue;
                }
                return filter.IsMatch(item);
            }

            return bLastRet;
            
        }

        private bool IsMatchSelf(UIItem item)
        {
            bool bAndJoin = true;
            bool bLastRet = true;


            Match match = _regex.Match(_strfilter);

            while (match.Success)
            {
                string name = match.Result("${name}");
                string cmpOp = match.Result("${cmpOp}");
                string value = match.Result("${value}");
                string join = match.Result("${join}");
                bAndJoin = (join == "||") ? false : true;

                if (!bLastRet && bAndJoin || (bLastRet && !bAndJoin))
                {
                    if (match.Success)
                    {
                        match = match.NextMatch();
                    }
                    continue;
                }
                bLastRet = false;


                #region compare here

                value = value.Trim('\'');

                switch (name)
                {
                    case "AcceleratorKey":
                        bLastRet = value == item.Current.AcceleratorKey;
                        break;
                    case "AccessKey":
                        bLastRet = value == item.Current.AccessKey;
                        break;
                    case "AutomationId":
                        bLastRet = value == item.Current.AutomationId;
                        break;
                    case "ClassName":
                        bLastRet = value == item.Current.ClassName;
                        break;
                    case "ControlType":
                        bLastRet = value == item.Current.ControlType.ProgrammaticName;
                        break;
                    case "FrameworkId":
                        bLastRet = value == item.Current.FrameworkId;
                        break;
                    case "HasKeyboardFocus":
                        bLastRet = bool.Parse(value) == item.Current.HasKeyboardFocus;
                        break;
                    case "HelpText":
                        bLastRet = value == item.Current.HelpText;
                        break;
                    case "IsContentElement":
                        bLastRet = bool.Parse(value) == item.Current.IsContentElement;
                        break;
                    case "IsControlElement":
                        bLastRet = bool.Parse(value) == item.Current.IsControlElement;
                        break;
                    case "IsEnabled":
                        bLastRet = bool.Parse(value) == item.Current.IsEnabled;
                        break;
                    case "IsKeyboardFocusable":
                        bLastRet = bool.Parse(value) == item.Current.IsKeyboardFocusable;
                        break;
                    case "IsOffscreen":
                        bLastRet = bool.Parse(value) == item.Current.IsOffscreen;
                        break;
                    case "IsPassword":
                        bLastRet = bool.Parse(value) == item.Current.IsPassword;
                        break;
                    case "IsRequiredForForm":
                        bLastRet = bool.Parse(value) == item.Current.IsRequiredForForm;
                        break;
                    case "ItemStatus":
                        bLastRet = value == item.Current.ItemStatus;
                        break;
                    case "ItemType":
                        bLastRet = value == item.Current.ItemType;
                        break;
                    case "LocalizedControlType":
                        bLastRet = value == item.Current.LocalizedControlType;
                        break;
                    case "Name":
                        bLastRet = value == item.Current.Name;
                        break;
                    case "ProcessId":
                        bLastRet = int.Parse(value) == item.Current.ProcessId;
                        break;
                    default:
                        bLastRet = false;
                        break;
                }
                #endregion compare here


                bLastRet = (cmpOp.Length == 2) ? !bLastRet : bLastRet;    //com.Length=2 !=

                match = match.NextMatch();


            }









            //item.Current.AutomationId
            return bLastRet;
        }

        public static implicit operator UIFilter(string queryString)
        {
            return new UIFilter(queryString);
        }

        public enum Join_Type
        {
            Join_And,
            Join_Or
        }

        private static Regex _regex;
        private List<UIFilter> _filters;

        
        public string _strfilter;
        private Join_Type _type;

        #region ICloneable Members

        public object Clone()
        {
            UIFilter filter = new UIFilter(_strfilter);
            filter._type = _type;
            filter._filters.AddRange(_filters);
            return filter;
        }

        #endregion
    }

}
